package scala.actors.multicast.test;

import scala.actors.Actor
import scala.actors.Actor._
import scala.actors.multicast.actorgroup._
import scala.actors.multicast.handlers._

import java.net._

import edu.ucla.cs.rpc.multicast.network.MulticastManager
import edu.ucla.cs.rpc.multicast.sequencer.fixed.FixedSequencer
import edu.ucla.cs.rpc.multicast.sequencer._

/**
  This program is derived from 
  http://www.scala-lang.org/docu/examples/files/pingpong.html
  , originally written by the LAMP/EFL group.
    
  @author Micah Wendell, Chase Covello, Philip Russell
  
  The purpose of this file is to have two Actors, Ping & Pong,
  communicate through the extended (ie with multicast functionality)
  Scala Actors library.
    
  Our goal was to leave the Ping & Pong classes untouched from the original
  example, and to modify the setup/cleanup code in the runnable code segment
  ONLY.
  
  We ended up having to add another parameter to Ping for test purposes.  This
  parameter indicated the number of Pongs that would be receiving Ping's messages.
  In practice, we would not wish to rely on knowing how many receivers we are
  corresponding with, but to simply verify that the multicast mechanism is working,
  this solution is exactly what we wanted.
  
  **/



object PingToPongs extends Application {
  /* SETUP for the MutlicastRPC framework
          The Ping & Pong groups communicate through 2 seperate channels,
             each comprising of a Sender, a Sequencer and a Destination, all
             of which is managed by a MulticastManager.
             
             We allocate two Sequencers and two MulticastManagers
             */
  val managers1: MulticastManager = new MulticastManager
  val seqs1: FixedSequencer = new FixedSequencer(managers1.getSocketAddress)
  val managers2: MulticastManager = new MulticastManager
  val seqs2: FixedSequencer = new FixedSequencer(managers2.getSocketAddress)
  /*
            then pass there contact information to the constructor of the ActorGroup
        that will "represent" the Ping and Pong objects to the framework
        NOTE: the Array allocation is necessary because Scala considers the type
        of the Java variable argument list to be an Array of objects. Unfortunately,
        this a small part of our implementation details.
  */
  val pingsGroup : ActorGroup = new MulticastActorGroup(
     "pingGroup",
     Array[java.net.SocketAddress](seqs1.getSocketAddress), 
          managers2.getSocketAddress)

  val pongsGroup : ActorGroup = new MulticastActorGroup(
      "pongGroup",
      Array[java.net.SocketAddress](seqs2.getSocketAddress), 
          managers1.getSocketAddress)
  /*
    Create a Ping and Pong object, and add them to their respective groups 
  */
    
  val pings = new Ping(100, 5, pingsGroup)
  pingsGroup += pings
  
  //add the Pong objects to ponggroup, starting each one
  var i = 0;
  while(i < 5)
  {
    val pongs = new Pong
    pongsGroup += pongs
    i += 1;
  }
  /*
    Start the Ping/Pong message bouncing behavior by sending the Start message.
  */
  pings ! Start
  
  Thread sleep 10000
  /* CLEANUP section.
    Tell the ActorGroups to Shutdown.
    If the program behaves correctly, the Ping and Pong objects should
    have terminated, sending the 'stop message to the calling environment.
    Explicitly shut down the Sequencers and MulticastManagers.
  */
  pingsGroup ! Shutdown
  pongsGroup ! Shutdown
  seqs1.shutdown
  seqs2.shutdown
  managers1.shutdown
  managers2.shutdown
}
